package com.yc.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.common.handler.MapResultHandler;
import com.yc.common.utils.AlyExcelUtil;
import com.yc.entity.*;
import com.yc.exception.CustomException;
import com.yc.mapper.ClassInfoMapper;
import com.yc.vo.Result;
import com.yc.mapper.UserMapper;
import com.yc.common.utils.Encrypt;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleService roleService;
    @Resource
    private PermissionService permissionService;
    @Autowired
    private LogService logService;
    @Resource
    private RedisTemplate redisTemplate;

    @Value("${initial-password.check}")
    private boolean checkPwd;
    @Resource
    private WxUser wxUser;
    @Resource
    private ClassInfoMapper classInfoMapper;


    /**
     * 登录
     *
     * @param username
     * @param password
     * @param identity
     * @return
     */
    public int  login(String username, String password, String identity, HttpServletRequest request) {
        String pwd = Encrypt.md5AndSha(password);
        if(username.length()<=15 && username.length()>=5){
            LambdaQueryWrapper wrapper1 = Wrappers.<User>lambdaQuery().eq(User::getUsername,username);
        if (username.length() <= 15 && username.length() >= 5) {
            wrapper1 = Wrappers.<User>lambdaQuery().eq(User::getUsername, username);
            User user1 = userMapper.selectOne(wrapper1);
            if (user1 == null) {
                //账号不存在请联系管理员,添加账号信息!
                throw new UsernameNotFoundException(" 账号不存在请联系管理员,添加账号信息!");
            }
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("username", username).eq("password", pwd);
            User user = userMapper.selectOne(wrapper);
            if (user == null) {
                //账号或密码错误或身份不匹配
                throw new BadCredentialsException(" Invalid username or password ");
            }
            request.getSession().setAttribute("user", user);
            request.getSession().setAttribute("userID", String.valueOf(user.getId()));
            wxUser.setUsername(username);
            redisTemplate.opsForHash().put("USERLOGINTOKEN", String.valueOf(user.getId()), request.getSession().getId());
            redisTemplate.expire("USERLOGINTOKEN", 80, TimeUnit.MINUTES);

            logService.log("用户 " + user.getUsername() + "登录", user.getNickname(), 1);
            //user.setPermission(getPermissions(user.getId()));
            user.setIdentity(1);
            return 1;
        } else {
            //账号识别失败请联系管理员!
            throw new AuthenticationServiceException("账号识别失败请联系管理员!");
        }
    }
        return 0;
    }
    /**
     * 查Systemuser的用户有没有微信信息
     * @param username
     * @return
     */
    public User selectSysByUsername(String username){
        User user = userMapper.selectByusername(username);
        return user;
    }

    /**
     * 如果没有Appid就添加
     * @param appid
     * @param wxpic
     * @param imei
     * @param username
     */
    public void insertByusername(String appid,String wxpic,String imei,String username){
        userMapper.insertByusername(appid, wxpic, imei, username);
    }

    /**
     * 查询用户名
     * @param username
     * @return
     */
    public Map<String,Object> queryMan(String username){
        Map<String, Object> map = userMapper.queryMan(username);
        String rolecode = (String) map.get("rolecode");
         if (rolecode.contains("ADMIN")){
            //超级管理员
            map.put("identity", 1);
        } else if (rolecode.contains("LEADER") && rolecode.contains("TEACHER")&&rolecode.contains("COUNSELLOR")) {
                // 即是领导 也是老师 还是辅导员
             map.put("identity", 4);
            } else if (rolecode.contains("LEADER") && rolecode.contains("TEACHER")) {
                // 即是领导 也是老师
             map.put("identity", 4);
            } else if (rolecode.contains("LEADER")) {
                //领导 1
             map.put("identity", 1);
            } else if (rolecode.contains("TEACHER")) {
                //老师
             map.put("identity", 3);
            } else if (rolecode.contains("COUNSELLOR")) {
                //辅导员
             map.put("identity", 2);
            }
        return map;
    }


    /**
     * 设置权限
     *
     * @param userId
     * @return
     */
    public List<Permission> getPermissions(Integer userId) {
        User user = getById(userId);
        List<Permission> permissions = new ArrayList<>();
        List<Long> role = user.getRole();
        if (role != null) {
            for (Object roleId : role) {
                Role realRole = roleService.getById((int) roleId);
                if (CollUtil.isNotEmpty(realRole.getPermission())) {
                    for (Object permissionId : realRole.getPermission()) {
                        Permission permission = permissionService.getById((int) permissionId);
                        if (permission != null && permissions.stream().noneMatch(p -> p.getPath().equals(permission.getPath()))) {
                            permissions.add(permission);
                        }
                    }
                }
            }
            user.setPermission(permissions);
        }
        return permissions;
    }

    /**
     * 根据用户名查询用户
     *
     * @param username
     * @return
     */
    public User getbyUsername(String username) {
        User one = getOne((Wrappers.<User>lambdaQuery().eq(User::getUsername, username)));
        one.setPermission(getPermissions(one.getId()));
        return one;
    }

    /**
     * 下载模板
     *
     * @param response
     * @return
     * @throws IOException
     */
    public Result<?> downloadTemplate(HttpServletResponse response) throws IOException {
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        org.springframework.core.io.Resource[] resources = resourcePatternResolver.
                getResources("classpath*:" + File.separator + "static" +
                        File.separator + "file" + File.separator + "addTeacher.xls");
        org.springframework.core.io.Resource resource = resources[0];
        InputStream inputStream = null;
        OutputStream out = null;
        try {
            //根据文件在服务器的路径读取该文件转化为流
            inputStream = resource.getInputStream();
            //创建一个Buffer字符串
            byte[] buffer = new byte[1024];
            Date date = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String time = simpleDateFormat.format(date);
            String fileName = "教师信息模板-" + time + ".xls";
            //设置文件ContentType类型，这样设置，会自动判断下载文件类型
            response.setContentType("multipart/form-data");
            //设置文件头：最后一个参数是设置下载文件名（设置编码格式防止下载的文件名乱码）
            response.setHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes("UTF-8"), "ISO8859-1"));
            out = response.getOutputStream();
            int b = 0;
            while (b != -1) {
                b = inputStream.read(buffer);
                //写到输出流(out)中
                out.write(buffer, 0, b);
            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("下载失败");
        } finally {
            try {
                inputStream.close();
                out.close();
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 密码比对
     *
     * @param user
     * @return
     */
    public Result compare(User user) {
        User user1 = userMapper.selectAllByUsername(user.getUsername());
        if (Encrypt.md5AndSha(user.getPassword()).equals(user1.getPassword())) {
            return Result.success(user);
        } else {
            return Result.error("错误");
        }
    }

    /**
     * 修改密码
     *
     * @param user
     * @return
     */
    public Result updateByName(User user) {
        String newPassword = Encrypt.md5AndSha(user.getPassword());
        userMapper.updatePasswordByUsername(newPassword, user.getUsername());
        return Result.success();
    }

    /**
     * 重置密码
     *
     * @param user
     * @return
     */
    public int resettingPwd(User user) {
        String newPassword = Encrypt.md5AndSha(user.getUsername());
        LambdaUpdateWrapper wrapper = Wrappers.<User>lambdaUpdate()
                .set(User::getPassword, newPassword).eq(User::getUsername, user.getUsername());
        return userMapper.update(null, wrapper);
    }

    /**
     * 根据学院名查询学院
     *
     * @return
     */
    public List<String> selectDeptNameByUdid(Long udid) {
        return userMapper.selectDeptNameByUdid(udid);
    }


    /**
     * 检查当前用户是否是初始密码
     *
     * @param request
     * @return
     */
    public int checkPassword(HttpServletRequest request) {
        if (checkPwd) {
            if (request.getSession().getAttribute("user") != null) {
                Object object = request.getSession().getAttribute("user");
                User user = (User) object;
                String password = Encrypt.md5AndSha(user.getUsername());
                LambdaQueryWrapper wrapper = Wrappers.<User>lambdaQuery()
                        .eq(User::getUsername, user.getUsername())
                        .eq(User::getPassword, password);
                if (userMapper.selectOne(wrapper) != null) {
                    return 1;
                } else {
                    return 0;
                }
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }


    /**
     * 查询所有的上课老师
     *
     * @return
     */
    public List<User> queryTeacher() {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(User::getRole, '3');
        List<User> users = userMapper.selectList(queryWrapper);
        return users;
    }

    /**
     * 获取所有的用户名和昵称 用户名为键 昵称为值
     *
     * @return
     */
    public Map<String, String> selectAllUser(){
        MapResultHandler<String, String> mapResultHandler = new MapResultHandler<>();
        userMapper.selectAllUserMap(mapResultHandler);
        return mapResultHandler.getMappedResults();
    }

    public int addUserList(List<User> userList){
        return userMapper.addUserList(userList);
    }


    /**
     * 上传数据
     *
     * @param inputStream 数据流
     * @return 是否成功
     */
    public int upload(InputStream inputStream, String uid) {
        //先判断是否先前有文件传输失败的情况而导致数据没有传输完毕的情况
        Object history = redisTemplate.opsForValue().get("line");
        int line = history == null ? 0 : (int) history;
        // 获取文件数据源
        List<Map<String, Object>> maps = AlyExcelUtil.excelToShopIdList(inputStream).get(0);
        // 要被添加角色的集合
        List<User> userList = new ArrayList<>();
        // 获取所有的角色
        Set<String> roles = roleService.selectAllRole();
        // 获得所有的系统用户
        Map<String, String> users = selectAllUser();
        // 判断是否重复上传
        boolean flag = true;

        for (int i = line; i < maps.size(); i++, line++) {
            Map<String, Object> map = maps.get(i);

            // 获取表中的数据并逐个赋值
            String username = String.valueOf(map.get("1"));
            String nickname = String.valueOf(map.get("2"));
            String sex = String.valueOf(map.get("3"));
            String phone = String.valueOf(map.get("4"));
            String email = String.valueOf(map.get("5"));
            String role = String.valueOf(map.get("6"));

            String regEx = "[_`~!@#$%^&*()+=|{}':;'.<>~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]|\n|\r|\t";
            String emailEx = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$";
            String regPhone = "^1[3456789]\\d{9}$";

            if (username == null || nickname == null || sex == null || role == null
            || username.matches(regEx) || nickname.matches(regEx) || (sex == null && !sex.matches(regEx)) || phone.matches(regEx)
            || role.matches(regEx) || (email == null && !email.matches(emailEx)) || (phone == null && !phone.matches(regPhone))){
                /*传输的过程中出现特殊字符导致数据传输中断，但是改正过来之后再次传输还从首位数据录入信息就显得太慢了
                所以记录错误的位置然后等待下一次传输的时候就从错误的地方开始录入信息
                */
                if (userList.size() > 0){
                    addUserList(userList);
                }
                redisTemplate.opsForValue().set("line", line, 5, TimeUnit.MINUTES);
                throw new CustomException("0", "第" + (line + 3) + "行的信息错误，请检查格式是否正确");
            }

            User user = new User();
            // 逐个赋值
            user.setUsername(username);
            // 使用md5加SHA对密码进行加密 默认为username
            user.setPassword(Encrypt.md5AndSha(username));
            user.setNickname(nickname);
            // 对性别进行判断
            if ("男性".equals(sex) || "男".equals(sex) ) {
                user.setSex(1);
            }else if ( "女性".equals(sex) || "女".equals(sex)){
                user.setSex(0);
            }else {
                user.setSex(null);
            }
            user.setPhone(phone);
            user.setEmail(email);
            // 判断角色是否存在
            List<Long> roleList = new ArrayList<>();
            roles.add("上课老师");
            // 默认都赋老师的权限
            if (roles.contains(role) || "上课老师".equals(role)){
                if ("辅导员".equals(role)){
                    roleList.add(2L);
                }else if("老师".equals(role) || "上课老师".indexOf(role) != -1){
                    roleList.add(3L);
                }else if ("领导".equals(role)){
                    roleList.add(4L);
                }
                user.setRole(roleList);
            }else if (role == null || role.length() <= 0 || "".equals(role) || "null".equals(role)){
                // 如果角色为空，就默认为老师
                roleList.add(3L);
                user.setRole(roleList);
            }else {
                if (userList.size() > 0){
                    addUserList(userList);
                }
                redisTemplate.opsForValue().set("line", line);
                throw new CustomException("0", "第" + (line + 3) + "行的角色错误，该角色不存在");
            }
            user.setCreateBy(uid);
            user.setUpdateBy(uid);
            // 判断是否有重复的 没有重复就添加到 集合中
            if (!users.containsKey(username)){
                userList.add(user);
            }
            if (line % 1000 == 0 && line > 0){
                flag = false;
                addUserList(userList);
                userList = new ArrayList<>();
            }
        }
        if (userList.size() <= 0 && flag){
            throw new CustomException("0", "文件重复上传");
        }else {
            addUserList(userList);
        }
        return 0;
    }

    /**
     * 查询所有系统用户
     * @param username
     * @param nickname
     * @param role
     * @return
     */
    public Page<User> selectAllUser(Page<User> page, String username, String nickname, String role) {
        Page<User> userPage = userMapper.selectAllUser(page, username, nickname, role);
        if (userPage.getRecords() == null || userPage.getRecords().size() <= 0) {
            throw new CustomException("0", "查询失败，暂无数据");
        }
        return userPage;
    }

    /**
     * 查出一年的课程总数
     * @param school_year
     * @return
     */
    public List<Map<String,Object>> selectByteaYear(String school_year,String mname,String yearnumber, String cname){
        List<Map<String, Object>> maps = userMapper.selectByteaYear(school_year,mname,cname,yearnumber);
        return maps;
    }
    /**
     * 查出上半年的课程总数
     * @param school_year
     * @return
     */
    public List<Map<String,Object>> selectByteaUpYear(String school_year,String mname,String yearnumber, String cname){
        List<Map<String, Object>> maps = userMapper.selectByteaUpYear(school_year,mname,cname,yearnumber);
        return maps;
    }

    /**
     * 查出下半年的课程总数
     * @param school_year
     * @return
     */
    public List<Map<String,Object>> selectByteaDownYear(String school_year,String mname,String yearnumber,String cname){
        List<Map<String, Object>> maps = userMapper.selectByteaDownYear(school_year,mname,cname,yearnumber);
        return maps;
    }

    /**
     * uniapp查出对应学期的课程总数
     * @param school_year
     * @param mname
     * @param yearnumber
     * @param cname
     * @return
     */
    public List<Map<String,Object>> selectByteaYearBywx(String school_year,String mname,String yearnumber,String cname){
        List<Map<String, Object>> maps = userMapper.selectByteaYearBywx(school_year,mname,cname,yearnumber);
        return maps;
    }


    /**
     * 查今天对应的学期
     * @param time
     * @return
     */
    public String queryNowTerm(String time){
        String term = userMapper.queryNowTerm(time);
        String nowTerm = term.substring(0, 9);
        return nowTerm;
    }

    /**
     * 查询所有学期
     * @return
     */
    public Map<String,Object> queryNowTermUpAndDown(){
        List<String> list = userMapper.queryNowTermAll();
        return null;
    }

    /**
     * 查询考勤分数不及格的
     * @return
     */
    public List<Map<String,Object>> queryfail(){
        //获取redis里面的数据
        Map<String,Object> allStuScoreData = (Map<String, Object>) redisTemplate.opsForValue().get("AllStuScoreData");
        //定义一个存储数据的数组，
        List<Map<String,Object>> data =new ArrayList<>();
        //循环redis里面的数据
        for (Map.Entry<String, Object> entry : allStuScoreData.entrySet()) {
            // 键为班级id
            String classname = entry.getKey();
            //获取这个键所有的值
            List<HashMap<String,Object>> value = (List<HashMap<String, Object>>) entry.getValue();
            //对所有值进行遍历
            for (HashMap<String, Object> map : value) {
                Map<String,Object> maps =new HashMap<>();
                //获取学号
                String stuid = (String) map.get("stuid");
                //获取分数
                int finalscore = (int) map.get("finalscore");
                //判断35以下的
                if (finalscore<=35){
                    Map<String,Object> stuMap = new HashMap<>();
                    stuMap.put("stuid",finalscore);
                    String nameBycid = classInfoMapper.classNameBycid(classname);
                    Map<String, Object> queryInfo = classInfoMapper.queryInfo(classname);
                    stuMap.put("nickname",queryInfo.get("nickname"));
                    stuMap.put("total",queryInfo.get("total"));
                    stuMap.put("studentID",stuid);
                    maps.put(nameBycid,stuMap);
                    data.add(maps);
                }
            }
        }
        return data;
    }

    /**
     * 根据专业查每个班级有多少35以下的人数
     * @param mname
     * @return
     */
    public List<Map<String, Object>> selectBnameAndCname(String mname) {
        // 查出来多个班级id
        List<Integer> cidList = classInfoMapper.selectCidByMname(mname);
        Map<String, Object> allStuScoreData = (Map<String, Object>) redisTemplate.opsForValue().get("AllStuScoreData");
        // 假设list是一个包含要获取数据的班级ID的列表
        List<String> classIdList = new ArrayList<>();
        List<List<Map<String,Object>>> lists =new ArrayList<>();
        for (Integer classId : cidList) {
            classIdList.add(Integer.toString(classId));
        }
// 创建一个存储班级数据的列表
        List<Map<String, Object>> classDataList = new ArrayList<>();
        Map<String,Object> returnDate =new HashMap<>();
        List<Map<String,Object>> finalData =new ArrayList<>();
        for (String classId : classIdList) {
            String nameBycid = classInfoMapper.classNameBycid(classId);
            List<Map<String, Object>> classData = (List<Map<String, Object>>) allStuScoreData.get(classId);
            if(null == classData|| classData.isEmpty()){
                return Collections.emptyList();
            }
            for (Map<String, Object> map : classData) {
                int finalscore = (int) map.get("finalscore");
                if (finalscore<=35){
                    classDataList.add(map);
                }
            }
            if (!(classDataList.size()==0)){
                returnDate.put(nameBycid,classDataList.size());
                classDataList.clear();
            }
        }
        finalData.add(returnDate);
        return finalData;
    }

    /**
     * 查具体班级的分数情况，分为5等
     * @param cname
     * @return
     */
    public  Map<String,Object>selectproportion(String cname){
        Integer id = classInfoMapper.selectIdByCname(cname);
        String idStr = String.valueOf(id);
        Map<String,Object> allStuScoreData = (Map<String, Object>) redisTemplate.opsForValue().get("AllStuScoreData");
        Map<String,Object> data =new HashMap<>();
        List<HashMap<String, Object>> studentsList = (List<HashMap<String, Object>>) allStuScoreData.get(idStr);
        List<Integer> down10 =new ArrayList<>();
        List<Integer> down20 =new ArrayList<>();
        List<Integer> down30 =new ArrayList<>();
        List<Integer> down40 =new ArrayList<>();
        List<Integer> down50 =new ArrayList<>();
        if (studentsList != null) {
            for (HashMap<String, Object> studentMap : studentsList) {
                String stuid = (String) studentMap.get("stuid");
                int finalscore = (int) studentMap.get("finalscore");if (finalscore <= 10) {
                    down10.add(finalscore);
                } else if (finalscore <= 20) {
                    down20.add(finalscore);
                } else if (finalscore <= 30) {
                    down30.add(finalscore);
                } else if (finalscore <= 40) {
                    down40.add(finalscore);
                } else if (finalscore <= 50) {
                    down50.add(finalscore);
                }
            }
        } else {
            log.warn("No data found for key: " + id);
        }
        data.put("优秀",down50);
        data.put("良好",down40);
        data.put("中等",down30);
        data.put("及格",down20);
        data.put("不及格",down10);
        return data;
    }

    /**
     * 课时量排名
     * @param school_year
     * @param mname
     * @return
     */
    public List<Map<String,Object>> Workload_ranking(String school_year,String mname){
        List<Map<String, Object>> maps = userMapper.Workload_ranking(school_year, mname);
        return maps;
    }

    /**
     * 查询前20名问题班级
     * @return
     */
    public List<Map<String,Object>> query_question_class(){
        List<Map<String, Object>> maps = userMapper.query_question_class();
        return maps;
    }

}
